use std::any::type_name;
use std::cell::Cell;
use std::marker::PhantomData;
use std::mem::{forget, MaybeUninit};
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use std::sync::{Mutex, Once};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

use crate::utils::thread_pool::MultiThreadTester;
use crate::utils::ThreadSafePtr;
use crate::{cache_cap, multi_tester, thread_safe_ptr, thread_safe_slice, to_mut_ref};

///实现一个简易延迟闭包，可以暂时缓存结果(生命周期等同于内部生命周期)
pub struct CacheCap<T> {
    val: Option<T>,
    get_val: Box<dyn Fn() -> T + Sync + Send + 'static>,
    once: Option<Once>,
}

impl<T> DerefMut for CacheCap<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.visit_mut()
    }
}

impl<T> Deref for CacheCap<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.visit()
    }
}

impl<T> CacheCap<T> {
    pub fn of(func: impl Fn() -> T + Send + Sync + 'static) -> Self {
        CacheCap {
            val: None,
            get_val: Box::new(func),
            once: Some(Once::new()),
        }
    }
    pub fn of_sync(func: impl Fn() -> T + Sync + Send + 'static) -> Self {
        CacheCap {
            val: None,
            get_val: Box::new(func),
            once: None,
        }
    }
    fn call_once(&mut self) -> &mut Self {
        if self.val.is_none() {
            if let Some(once) = self.once.as_mut() {
                once.call_once(|| {
                    self.val.replace(self.get_val.deref()());
                });
            } else {
                if self.val.is_none() {
                    self.val.replace(self.get_val.deref()());
                }
            }
        }
        self
    }

    pub fn visit(&self) -> &T {
        to_mut_ref!(self, Self).call_once().val.as_ref().unwrap()
    }

    pub fn visit_mut(&self) -> &mut T {
        to_mut_ref!(self, Self).call_once().val.as_mut().unwrap()
    }

    pub fn get(mut self) -> T {
        self.call_once();
        self.val.take().unwrap()
    }
}


#[test]
fn test() {
    thread_safe_ptr! {
        let atomic = AtomicUsize::new(0);
        let msg = String::from("ok");
        let cap = cache_cap!(atomic.fetch_add(1,Ordering::SeqCst));
    }
    multi_tester!({
        println!("{}", cap.visit());
    });
}